/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file t4t_nfcee_act.c
 * @brief T4T EE模块实现
 */
#include "discover_int.h"
#include "ee_int.h"
#include "nfa_discover.h"
#include "nci_base.h"
#include "nci_data.h"
#include "nci_feature.h"
#include "nci_utils.h"
#include "nfa_ee.h"
#include "nfa_utils.h"
#include "nfc_config_api.h"
#include "nfc_osi_api.h"
#include "t4t_api.h"

#if IS_FEATURE_ON(NCI_FEATURE_EE_T4T)

#define T4T_APDU_HEAD_LEN 5

typedef enum {
    IDLE,
    BUSY
} tT4TEE_STATE;

const static uint8_t s_t4t_v10_aid[T4T_NDEF_AID_LEN] = {
    0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00};
const static uint8_t s_t4t_v20_aid[T4T_NDEF_AID_LEN] = {
    0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};

static tT4TEE_STATE s_t4tee_state = IDLE;
static tMUTEX s_t4tee_lock = MUTEX_INIT_VAL("t4tee");
static uint8_t s_t4tee_ver = 0x20;
static uint8_t s_t4tee_conn = 0;
static bool s_restart_rf = false;

#define GET_T4TEE_LOCK_OR_RETURN(ret) \
    if (osi_mutex_lock(&s_t4tee_lock) != NFC_STATUS_OK) { \
        NFCLOG_E("GET_T4TEE_LOCK_OR_RETURN failed"); \
        return ret; \
    }

#define GET_T4TEE_LOCK() GET_T4TEE_LOCK_OR_RETURN(NCI_STATUS_EXT_GET_LOCK_FAILED)

#define RELEASE_T4TEE_LOCK() \
    if (osi_mutex_unlock(&s_t4tee_lock) != NFC_STATUS_OK) { \
        NFCLOG_E("RELEASE_T4TEE_LOCK failed"); \
    }

tNCI_STATUS transmit_t4tee(tNCI_BUF *cmd, tNCI_BUF *rsp) {
    if (!s_t4tee_conn) {
        NFCLOG_E("invalid conn id: %d", s_t4tee_conn);
        return NCI_STATUS_EXT_NOT_INITIALIZED;
    }
    tNCI_STATUS ret = nci_data_channel_transmit(s_t4tee_conn, cmd, rsp, NCI_DEFAULT_WAIT_TIME);
    return ret;
}

static tT4T_TARGET s_t4tee_target = {
    .transmit = transmit_t4tee,
};

/**
 * @brief 选择NFCC内部的T4T EE应用
 */
static tNCI_STATUS select_t4t_application() {
    NFCLOG_D("Enter.");
    if (s_t4tee_ver == T4T_VERSION_1_0) {
        return t4t_select_application(&s_t4tee_target, s_t4t_v10_aid, T4T_NDEF_AID_LEN, NULL);
    }
    return t4t_select_application(&s_t4tee_target, s_t4t_v20_aid, T4T_NDEF_AID_LEN, NULL);
}

/**
 * @brief 选择T4T EE应用中的文件
 *
 * @param[in] file_id 期望选中的文件ID
 */
static tNCI_STATUS select_t4t_file(uint16_t file_id) {
    NFCLOG_D("Enter: file_id 0x%04X", file_id);
    uint8_t p2 = T4T_P2_FIRST_OR_ONLY_0C;
    if (s_t4tee_ver == T4T_VERSION_1_0) {
        p2 = T4T_P2_FIRST_OR_ONLY_00;
    }
    return t4t_select_file(&s_t4tee_target, file_id, p2, NULL);;
}

/**
 * @brief 读取T4T EE应用中的文件的内容长度
 */
static uint16_t read_t4t_file_len() {
    uint16_t len = 0;
    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = t4t_read_binary(&s_t4tee_target, 0x00, T4T_FILE_SIZE_LEN, true, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t4t_read_binary failed: %d", ret);
    } else {
        uint16_t sw = (rsp->data[rsp->len - 2] << 8) | rsp->data[rsp->len - 1];
        if (sw == T4T_SW_OK) {
            len = (rsp->data[0] << 8) | rsp->data[1];
        }
        free_nci_buf(rsp);
    }
    return len;
}

/**
 * @brief 读取T4T EE应用中的文件的内容
 */
static tNCI_STATUS read_t4t_file(uint16_t offset, uint8_t *buffer, uint32_t len) {
    tNCI_BUF *rsp = NULL;
    if (!buffer || !len) {
        NFCLOG_E("invalid buffer!");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_STATUS ret = t4t_read_binary(&s_t4tee_target, offset, len, true, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t4t_read_binary failed: %d", ret);
        return ret;
    } else {
        uint16_t sw = (rsp->data[rsp->len - 2] << 8) | rsp->data[rsp->len - 1];
        if (sw == T4T_SW_OK) {
            // 拷贝时，减去2个状态字
            if (!osi_memcpy_s(buffer, len, rsp->data, rsp->len - T4T_SW_LEN)) {
                NFCLOG_E("osi_memcpy_s failed!");
                ret = NCI_STATUS_EXT_COPY_FAILED;
            }
        }
    }
    free_nci_buf(rsp);
    return ret;
}

/**
 * @brief 更新T4T EE应用中的文件的内容长度
 */
static tNCI_STATUS update_t4t_nlen(uint32_t len) {
    NFCLOG_E("Enter, len = %u", len);
    // offset=0, data_len=NLEN_SIZE=2, 转换为大端模式下发数据
    uint8_t data[2];
    uint8_t* p_data = data;
    UINT16_TO_STREAM_BE(p_data, len);
    tNCI_STATUS ret = t4t_write_binary(&s_t4tee_target, 0x00, 0x02, data, NULL);
    return ret;
}

/**
 * @brief 更新T4T EE应用中的文件的内容
 */
static tNCI_STATUS write_t4t_file(const uint8_t *data, uint16_t len) {
    tNCI_STATUS ret = t4t_write_binary(&s_t4tee_target, T4T_FILE_SIZE_LEN, len, data, NULL);
    return ret;
}

/**
 * @brief 向T4T EE应用发送APDU指令
 */
static tNCI_STATUS send_apdu(const uint8_t *cmd, uint16_t len, tNCI_RSP* rsp) {
    tT4T_APDU apdu;
    apdu.cla = cmd[0];
    apdu.ins = cmd[1];
    apdu.p1 = cmd[2];
    apdu.p2 = cmd[3];
    apdu.lc = cmd[4];
    if (apdu.lc > 0) {
        apdu.p_dat = &cmd[5];
    }
    if (T4T_APDU_HEAD_LEN + apdu.lc < len) {
        apdu.le_present = true;
        apdu.le = cmd[len-1];
    } else {
        apdu.le_present = false;
    }
    tNCI_BUF *buff = NULL;
    tNCI_STATUS ret = t4t_send_apdu(&s_t4tee_target, &apdu, &buff);
    if (ret != NCI_STATUS_OK || !buff) {
        NFCLOG_E("t4t_send_apdu falied!");
        goto cleanup;
    }
    rsp->data = osi_malloc(buff->len);
    if (!rsp->data) {
        NFCLOG_E("osi_malloc falied!");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    if (!osi_memcpy_s(rsp->data, buff->len, buff->data, buff->len)) {
        NFCLOG_E("osi_memcpy_s falied!");
        nfa_utils_free_rsp(rsp, true);
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    rsp->len = buff->len;
cleanup:
    free_nci_buf(buff);
    return ret;
}

/**
 * @brief 建立和T4T EE通信的环境，包括关闭RF、打开通道
 */
static tNCI_STATUS setup() {
    GET_T4TEE_LOCK();
    tNCI_STATUS ret = NCI_STATUS_EXT_STATE_INCORRECT;
    if (s_t4tee_state == BUSY) {
        NFCLOG_W("t4t ee is in busy state!");
        goto unlock;
    }
    tNCI_RFST rfst = nfa_rf_get_state();
    if (rfst != NCI_RFST_IDLE) {
        ret = nfa_rf_stop_discovery();
        if (ret == NCI_STATUS_OK) {
            s_restart_rf = true;
        } else {
            NFCLOG_E("stop rf discovery failed!");
            goto unlock;
        }
    }
    if (nfa_ee_open_channel(NCI_T4T_NFCEE_ID, NCI_NFCEE_PROTOCOL_APDU) == NCI_STATUS_OK) {
        s_t4tee_conn = nfa_ee_get_channel_id(NCI_T4T_NFCEE_ID);
        s_t4tee_state = BUSY;
        ret = select_t4t_application();
    }
unlock:
    RELEASE_T4TEE_LOCK();
    return ret;
}

/**
 * @brief 关闭和T4T EE通信的环境，包括重新打开RF、关闭通道
 */
static tNCI_STATUS cleanup() {
    GET_T4TEE_LOCK();
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    if (s_t4tee_state == IDLE) {
        NFCLOG_W("t4t ee is in IDLE state!");
        goto unlock;
    }
    ret = nfa_ee_close_channel(NCI_T4T_NFCEE_ID);
    s_t4tee_conn = 0;
    s_t4tee_state = IDLE;
    if (s_restart_rf) {
        nfa_rf_start_discovery();
        s_restart_rf = false;
    }
unlock:
    RELEASE_T4TEE_LOCK();
    return ret;
}


/**
 * @brief 向T4T Ndef NFCEE中读取NDEF数据
 *
 * @param[in] file_id 操作的目标文件ID
 * @param[inout] buffer 接收返回的NDEF数据
 *
 * @return 成功返回NCI_STATUS_OK，否则返回对应错误码
 */
tNCI_STATUS nfa_t4tee_read(uint16_t file_id, tNCI_RSP* buffer) {
    if (!buffer) {
        NFCLOG_E("invalid param!");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (rf_lock() != NCI_STATUS_OK) {
        NFCLOG_E("get rf lock failed");
        return NCI_STATUS_EXT_GET_LOCK_FAILED;
    }
    if (setup() != NCI_STATUS_OK) {
        NFCLOG_E("setup failed!");
        rf_unlock();
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    // TODO: if necessary to read CC file?
    // 选择CC文件
    tNCI_STATUS ret = select_t4t_file(T4T_CC_FILE_ID);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("select cc file failed!");
        goto cleanup;
    }
    read_t4t_file_len();
    // read_t4t_file();

    // 选择NDEF文件
    ret = select_t4t_file(file_id);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("select file 0x%04X failed!", file_id);
        goto cleanup;
    }
    uint16_t len = read_t4t_file_len();
    if (!len) {
        NFCLOG_W("empty file.");
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
    buffer->data = osi_malloc(len);
    if (!buffer->data) {
        NFCLOG_E("osi_malloc failed.");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    buffer->len = len;
    ret = read_t4t_file(T4T_FILE_SIZE_LEN, buffer->data, buffer->len);
    if (ret != NCI_STATUS_OK) {
        nfa_utils_free_rsp(buffer, true);
    }
cleanup:
    cleanup();
    rf_unlock();
    return ret;
}

/**
 * @brief 向T4T Ndef NFCEE中写入NDEF数据
 *
 * @param[in] file_id 操作的目标文件ID
 * @param[in] data 传入的数据的指针
 * @param[in] len 传入的数据的长度
 *
 * @return 成功返回NCI_STATUS_OK，否则返回对应错误码
 */
tNCI_STATUS nfa_t4tee_write(uint16_t file_id, uint8_t* data, uint32_t len) {
    if (!data || !len) {
        NFCLOG_E("invalid param!");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (rf_lock() != NCI_STATUS_OK) {
        NFCLOG_E("get rf lock failed");
        return NCI_STATUS_EXT_GET_LOCK_FAILED;
    }
    if (setup() != NCI_STATUS_OK) {
        NFCLOG_E("setup failed!");
        rf_unlock();
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    // TODO: if necessary to read CC file?
    // 选择CC文件
    tNCI_STATUS ret = select_t4t_file(T4T_CC_FILE_ID);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("select cc file failed!");
        goto cleanup;
    }
    read_t4t_file_len();
    // read_t4t_file();

    // 选择NDEF文件
    ret = select_t4t_file(file_id);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("select file 0x%04X failed!", file_id);
        goto cleanup;
    }
    // 复位NLEN
    ret = update_t4t_nlen(0x0000);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("update Nlen failed!");
        goto cleanup;
    }
    ret = write_t4t_file(data, len);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("write_t4t_file failed");
        goto cleanup;
    }
    // 更新NLEN为写入的数据长度
    ret = update_t4t_nlen(len);
cleanup:
    cleanup();
    rf_unlock();
    return ret;
}

/**
 * @brief 向T4T Ndef NFCEE发送APDU指令，并获取回复
 *
 * @param[in]    cmd 传入的APDU指令数据指针
 * @param[in]    len 传入的指令的长度
 * @param[inout] rsp 储存APDU指令的回复
 *
 * @return 成功返回NCI_STATUS_OK，否则返回对应错误码
 */
tNCI_STATUS nfa_t4tee_send_apdu(uint8_t* cmd, uint32_t len, tNCI_RSP* rsp) {
    if (!cmd || len < T4T_APDU_HEAD_LEN || !rsp) {
        NFCLOG_E("invalid param!");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (rf_lock() != NCI_STATUS_OK) {
        NFCLOG_E("get rf lock failed");
        return NCI_STATUS_EXT_GET_LOCK_FAILED;
    }
    if (setup() != NCI_STATUS_OK) {
        NFCLOG_E("setup failed!");
        rf_unlock();
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    // TODO: if necessary to read CC file?
    // 选择CC文件
    tNCI_STATUS ret = select_t4t_file(T4T_CC_FILE_ID);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("select cc file failed!");
        goto cleanup;
    }
    read_t4t_file_len();
    // read_t4t_file();

    ret = send_apdu(cmd, len, rsp);
cleanup:
    cleanup();
    rf_unlock();
    return ret;
}

/**
 * @brief 获取T4T Ndef NFCEE默认的路由电源状态
 *
 * @return 返回T4T Ndef NFCEE默认的路由电源状态
 */
uint8_t nfa_t4tee_get_power_state() {
    return nfc_config_get()->vendor_cf.t4t_nfcee_aid_power_state;
}

tNCI_STATUS t4tee_init() {
    if (osi_mutex_init_with_attr(&s_t4tee_lock, true) != NFC_STATUS_OK) {
        NFCLOG_E("init mutex failed");
        return NCI_STATUS_EXT_FAILED;
    }
    // TODO: get t4t version from config
    return NCI_STATUS_OK;
}

tNCI_STATUS t4tee_deinit() {
    osi_mutex_deinit(&s_t4tee_lock);
    return NCI_STATUS_OK;
}

tNCI_EXTERN_EE g_t4tee = {
    .id = NCI_T4T_NFCEE_ID,
    .init = t4tee_init,
    .deinit = t4tee_deinit
};

#endif // #if IS_FEATURE_ON(NCI_FEATURE_EE_T4T)